using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace SpoonCore2.Tools
{
	public class BlockingRingBuffer<T>
	{
		private static readonly bool Debug = false;
		private int _readPos;
		private int _writePos;
		private readonly T[] _data;
		private readonly AutoResetEvent _reseterReader = new AutoResetEvent(false);
		private readonly AutoResetEvent _reseterWriter = new AutoResetEvent(false);
		private readonly Mutex _locker = new Mutex();

		public BlockingRingBuffer(int size)
		{
			_data = new T[size];
		}

		public void Enqueue(T item)
		{
			_locker.WaitOne();
			while (_data.Length - 1 == (_writePos - _readPos + _data.Length) % _data.Length)
			{
				_locker.ReleaseMutex();
				_reseterWriter.WaitOne();
				_locker.WaitOne();
			}

			_data[_writePos++] = item;
			_writePos %= _data.Length;
			if(Debug) ColorConsole.WriteLine(Thread.CurrentThread.Name + " Written: " + item);

			_reseterWriter.Reset();
			_locker.ReleaseMutex();
			_reseterReader.Set();
		}

		public T Dequeue()
		{
			_locker.WaitOne();
			while (_writePos == _readPos)
			{
				_locker.ReleaseMutex();
				_reseterReader.WaitOne();
				_locker.WaitOne();
			}

			T res = _data[_readPos];
			_data[_readPos] = default(T);
			_readPos++;

			_readPos %= _data.Length;
			if (Debug) ColorConsole.WriteLine(Thread.CurrentThread.Name + " Read: " + res);

			_reseterReader.Reset();
			_locker.ReleaseMutex();
			_reseterWriter.Set();

			return res;
		}

		public int Count { get { return (_writePos - _readPos + _data.Length) % _data.Length; } }
		public int Size { get { return _data.Length; } }
	}
}